#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <vector>
#include<string>
#include <mutex>
#include <functional>
#include <memory>
using  namespace std;
namespace lnb
{
	template<class T>
	class auto_ptr
	{
	public:
		auto_ptr(T* ptr)
			:_ptr(ptr)
		{}
		T& operator*()
		{
			return *_ptr;
		}

		auto_ptr(auto_ptr& ap)
			:_ptr(ap._ptr)
		{
			ap._ptr = nullptr;
		}

		auto_ptr& operator=(auto_ptr& ap)
		{
			if (this != ap)
			{
				delete _ptr;
				_ptr = ap._ptr;
				ap._ptr = nullptr;
			}
		}

		T* operator->()
		{
			return _ptr;
		}

		~auto_ptr()
		{
			delete _ptr;
		}

	private:
		T* _ptr;
	};


	template<class T>
	class unique_ptr
	{
	public:
		unique_ptr(T* ptr)
			:_ptr(ptr)
		{}
		T& operator*()
		{
			return *_ptr;
		}

		T* operator->()
		{
			return _ptr;
		}

		unique_ptr(const unique_ptr& ap) = delete;
		unique_ptr& operator=(const unique_ptr& ap) = delete;
		~unique_ptr()
		{
			delete _ptr;
		}

	private:
		T* _ptr;
	};



	template<class T>
	class shared_ptr
	{
	public:
		shared_ptr(T* ptr=nullptr)
			:_ptr(ptr)
			, _pcount(new int(1))
			, _mtx(new mutex)
		{}
		
		template<class T,class D>
		shared_ptr(T* ptr,D d)
			:_ptr(ptr)
			, _pcount(new int(1))
			, _mtx(new mutex)
			,_del(d)
		{}
		T& operator*()
		{
			if (_ptr == nullptr)
			{
				throw "nullptr";
			}
			return *_ptr;
		}

		T* operator->()
		{
			if (_ptr == nullptr)
			{
				throw "nullptr";
			}
			return _ptr;
		}
		shared_ptr(const shared_ptr<T>& sp)
			:_ptr(sp._ptr),
			_pcount(sp._pcount)
			,_mtx(sp._mtx)
		{
			AddCount();
		}
		void Release()
		{
			bool into = false;
			_mtx->lock();
			if (--(*_pcount) == 0)
			{
				_del(_ptr);
				delete _pcount;
				into = true;	
			}
			_mtx->unlock();
			if (into)
			{
				delete _mtx;
			}
		}

		T* get()const
		{
			return _ptr;
		}
		int use_count()
		{
			return *_pcount;
		}

		void AddCount()
		{
			_mtx->lock();
			(*_pcount)++;
			_mtx->unlock();
		}
		shared_ptr<T>& operator=(const shared_ptr<T>& sp)
		{
			if (this->_ptr!= sp._ptr)
			{
				Release();
				_ptr = sp._ptr;
				_pcount = sp._pcount;
				_mtx = sp._mtx;
				AddCount();
			}
			return *this;
		}
		~shared_ptr()
		{
			Release();
		}

	private:
		T* _ptr;
		int* _pcount;
		mutex* _mtx;
		function<void(T*)> _del = [](T* ptr)->void {delete ptr; };
	};

	template<class T>
	class weak_ptr
	{
	public:
		weak_ptr()
			:_ptr(nullptr)
		{}
		weak_ptr(const lnb::shared_ptr<T>& sp)
			:_ptr(sp.get())
		{}
		T& operator*()
		{
			return *_ptr;
		}

		T* operator->()
		{
			return _ptr;
		}

		//weak_ptr(const weak_ptr& ap);
		weak_ptr<T>& operator=(const lnb::shared_ptr<T>& sp)
		{
			_ptr=sp.get();
			return *this;
		}
		

	private:
		T* _ptr;
	};


}